package com.tanhua.server.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.PageUtil;
import com.github.tobato.fastdfs.domain.conn.FdfsWebServer;
import com.github.tobato.fastdfs.domain.fdfs.StorePath;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import com.tanhua.autoconfig.template.OssTemplate;
import com.tanhua.commons.utils.Constants;
import com.tanhua.dubbo.api.*;
import com.tanhua.model.domain.UserInfo;
import com.tanhua.model.mongo.FocusUser;
import com.tanhua.model.mongo.UserComment;
import com.tanhua.model.mongo.Video;
import com.tanhua.model.mongo.VideoLike;
import com.tanhua.model.vo.*;
import com.tanhua.server.exception.BusinessException;
import com.tanhua.server.interceptor.UserHolder;
import org.apache.commons.lang.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.bson.types.ObjectId;
import org.checkerframework.checker.units.qual.C;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author ck
 * @date 2021/11/18 14:32
 */

@Service
public class SmallVideosService {


    @Autowired
    private FdfsWebServer webServer;

    @Autowired
    private FastFileStorageClient client;

    @Autowired
    private OssTemplate ossTemplate;

    @DubboReference
    private VideoApi videoApi;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @DubboReference
    private UserInfoApi userInfoApi;

    @DubboReference
    private FocusUserApi focusUserApi;

    @DubboReference
    private VideoLikeApi videoLikeApi;

    @DubboReference
    private UserCommentApi userCommentApi;

    @Autowired
    private MqMessageService mqMessageService;
    /**
     * 上传视频
     *
     * @param videoThumbnail 封面图片
     * @param videoFile      实体文件
     */
    public void saveVideos(MultipartFile videoThumbnail, MultipartFile videoFile) throws IOException {
        if (videoFile.isEmpty() || videoThumbnail.isEmpty()) {
            throw new BusinessException(ErrorResult.error());
        }
        //1、将视频上传到FastDfs上,获取访问url
        String filename = videoFile.getOriginalFilename();
        filename = filename.substring(filename.lastIndexOf(".") + 1);
        StorePath path = client.uploadFile(videoFile.getInputStream(), videoFile.getSize(), filename, null);
        String videoUrl = webServer.getWebServerUrl() + path.getFullPath();
        //2、将封面图片上传到阿里云OSS，获取访问url
        String imageUrl = ossTemplate.upload(videoThumbnail.getOriginalFilename(), videoThumbnail.getInputStream());
        //3、构建videos对象
        Video video = new Video();
        video.setUserId(UserHolder.getUserId());
        video.setPicUrl(imageUrl);
        video.setVideoUrl(videoUrl);
        video.setText("我就是我,不一样的烟火");
        //4、调用API保存数据
        String videoId = videoApi.save(video);
        if (StringUtils.isEmpty(videoId)) {
            throw new BusinessException(ErrorResult.error());
        }

        //发送消息
        mqMessageService.sendLogMessage(UserHolder.getUserId(),"0301","video",videoId);
    }

    //查询视频列表
    @Cacheable(value = "videos",
            key = "T(com.tanhua.server.interceptor.UserHolder).getUserId()+'_'+#page+'_'+#pagesize")
    //userId_page_pagesize
    public PageResult queryVideoList(Integer page, Integer pagesize) {
        //1、查询redis数据
        String redisKey = Constants.VIDEOS_RECOMMEND + UserHolder.getUserId();
        String redisValue = redisTemplate.opsForValue().get(redisKey);
        //2、判断redis数据是否存在，判断redis中数据是否满足本次分页条数
        List<Video> list = new ArrayList<>();
        int redisPages = 0;
        if (!StringUtils.isEmpty(redisValue)) {
            //3、如果redis数据存在，根据vid查询数据
            String[] values = redisValue.split(",");
            //判断当前页起始条数是否小于数组总数
            if ((page - 1) * pagesize < values.length) {
                List<Long> vids = Arrays.stream(values).skip((page - 1) * pagesize).limit(pagesize)
                        .map(e -> Long.valueOf(e))
                        .collect(Collectors.toList());
                //5、调用api根据pid数组查询动态数据
                list = videoApi.findVideosByVids(vids);
            }
            redisPages = PageUtil.totalPage(values.length, pagesize);
        }

        //4、如果redis数据不存在，分页查询视频数据
        if (list.isEmpty()) {
            //page的计算规则 传入的页码 --redis查询的总页数
            //传递的页码应该为page -redisPages
            list = videoApi.queryVideoList(page - redisPages, pagesize);
        }
        //5、提取视频列表中所有用户id
        List<Long> userIds = CollUtil.getFieldValues(list, "userId", Long.class);
        //6、查询用户信息
        List<VideoVo> vos = new ArrayList<>();
        Map<Long, UserInfo> userInfos = userInfoApi.findByIds(userIds, null);

        for (Video video : list) {

            String key = Constants.VIDEO_LIKE_HASHKEY + video.getUserId();
            String hashKey = Constants.VIDEO_LIKE_HASHKEY + UserHolder.getUserId();

//            Boolean hasLiked = videoLikeApi.hasLiked(UserHolder.getUserId(), video.getUserId());
            UserInfo userInfo = userInfos.get(video.getUserId());
            if (userInfo != null) {
                VideoVo videoVo = VideoVo.init(userInfo, video);
                if (redisTemplate.opsForHash().hasKey(key,hashKey)){
                    videoVo.setHasLiked(1);
                }else {
                    videoVo.setHasLiked(0);
                }
                if (focusUserApi.hasFocus(UserHolder.getUserId(),video.getUserId())){
                    videoVo.setHasFocus(1);
                }else {
                    videoVo.setHasFocus(0);
                }
                vos.add(videoVo);
            }
        }
        //7、构建返回值
        return new PageResult(page, pagesize, 0l, vos);
    }

    //关注发视频的人
    public void userFocus(Long followUserId) {
        Long userId = UserHolder.getUserId();
        //判断被关注id和用户id是不是同一个人 自己不能关注自己
        if (!followUserId.equals(userId)) {
            //判断是否已经关注此人
            Boolean flag = focusUserApi.hasFocus(userId, followUserId);
            if (flag) {
                throw new BusinessException(ErrorResult.error());
            }
            //调用api保存 数据到mongodb
            FocusUser focusUser = new FocusUser();
            focusUser.setCreated(System.currentTimeMillis());
            focusUser.setUserId(userId);
            focusUser.setFollowUserId(followUserId);
            focusUserApi.save(focusUser);
            //拼接redis的key，将用户的点赞状态存入redis
            String key = Constants.FOCUS_USER + "_" + followUserId;
            String hashKey = Constants.FOCUS_USER + "_" + userId;
            redisTemplate.opsForHash().put(key, hashKey, "关注");
        }
    }

    //取消关注发视频的人
    public void userUnFocus(Long followUserId) {
        Long userId = UserHolder.getUserId();
        String key = Constants.FOCUS_USER + "_" + followUserId;
        String hashKey = Constants.FOCUS_USER + "_" + userId;
        //判断是否已经关注此人
        Boolean flag = focusUserApi.hasFocus(userId, followUserId);
        if (!flag) {
            throw new BusinessException(ErrorResult.error());
        }
        focusUserApi.delete(userId,followUserId);
        redisTemplate.opsForHash().delete(key,hashKey);
    }
//    视频用户点赞
    public void userLike(ObjectId id) {
        //获取mongodb中存储的video对象
        Video video = videoApi.find(id);
        //判断用户是否已经点赞
        Boolean flag = videoLikeApi.hasLiked(UserHolder.getUserId(),video.getUserId());
        if (flag){
            throw new BusinessException(ErrorResult.error());
        }
        VideoLike videoLike = new VideoLike();
        videoLike.setVid(video.getVid());
        videoLike.setVUserId(video.getUserId());
        videoLike.setUserId(UserHolder.getUserId());
        videoLike.setCreated(System.currentTimeMillis());
        videoLike.setLiked(true);
        videoLikeApi.save(videoLike);
        //拼接redis的key，将用户的点赞状态存入redis
        String key = Constants.VIDEO_LIKE_HASHKEY + video.getUserId();
        String hashKey = Constants.VIDEO_LIKE_HASHKEY + UserHolder.getUserId();
        redisTemplate.opsForHash().put(key, hashKey, "点赞");
    }

    //取消点赞
    public void userDisLike(ObjectId id) {
        //获取mongodb中存储的video对象
        Video video = videoApi.find(id);
        //判断用户是否已经点赞
        Boolean flag = videoLikeApi.hasLiked(UserHolder.getUserId(),video.getUserId());
        if (!flag){
            throw new BusinessException(ErrorResult.error());
        }
        VideoLike videoLike = videoLikeApi.find(UserHolder.getUserId());
        videoLikeApi.delete(videoLike);
        //拼接redis的key，将用户的点赞状态存入redis
        String key = Constants.VIDEO_LIKE_HASHKEY + video.getUserId();
        String hashKey = Constants.VIDEO_LIKE_HASHKEY + UserHolder.getUserId();
        redisTemplate.opsForHash().delete(key,hashKey);
    }

    //分页查询评论列表
    public PageResult userCommentsList(ObjectId id, Integer page, Integer pagesize) {
        Video video = videoApi.find(id);
        //调用api查询评论列表
        List<UserComment> commentList = userCommentApi.find(video.getUserId(),page,pagesize);
        if (CollUtil.isEmpty(commentList)){
            return new PageResult();
        }
        //获取所有用户id，调用userinfo查询用户详情
        List<Long> ids = CollUtil.getFieldValues(commentList, "userId", Long.class);
        Map<Long, UserInfo> infoMap = userInfoApi.findByIds(ids, null);
        //构造vo
        List<UserCommentVo> vos = new ArrayList<>();
        for (UserComment userComment : commentList) {
            String key = Constants.VIDEO_COMMENT_HASHKEY + "_" + userComment.getVUserId();
            String hashKey = Constants.VIDEO_COMMENT_HASHKEY + "_" + UserHolder.getUserId();
            UserInfo userInfo = infoMap.get(userComment.getUserId());
            if (userInfo != null){
                UserCommentVo vo = new UserCommentVo();
                vo.setId(userComment.getId().toHexString());
                vo.setAvatar(userInfo.getAvatar());
                vo.setNickname(userInfo.getNickname());
                vo.setContent(userComment.getContent());
                vo.setCreateDate(new SimpleDateFormat("yyyy-MM-dd HH-mm-ss").format(userComment.getCreated()));
                vo.setLikeCount(userComment.getLikeCount());
                if (redisTemplate.opsForHash().hasKey(key,hashKey)){
                    vo.setHasLiked(1);
                }else {
                    vo.setHasLiked(0);
                }
                vos.add(vo);
            }
        }
        return new PageResult(page,pagesize,0l,vos);
    }

    //发布评论
    public void upComments(ObjectId id, String content) {
        //根据视频id查询视频
        Video video = videoApi.find(id);
        //构造UserComment
        UserComment userComment = new UserComment();
        userComment.setUserId(UserHolder.getUserId());
        userComment.setContent(content);
        userComment.setVUserId(video.getUserId());
        userComment.setVid(video.getVid());
        userComment.setCreated(System.currentTimeMillis());
        userCommentApi.save(userComment);
    }

    //评论点赞
    public void likeComments(ObjectId id) {
        String type = "zan";
        //返回用户评论数据
        UserComment userComment = userCommentApi.likeOrUnlike(id,type);

        String key = Constants.VIDEO_COMMENT_HASHKEY + "_" + userComment.getVUserId();
        String hashKey = Constants.VIDEO_COMMENT_HASHKEY + "_" + UserHolder.getUserId();
        redisTemplate.opsForHash().put(key, hashKey, "评论");
    }

    public void dislikeComments(ObjectId objectId) {

        String type = "buZan";
        //返回用户评论数据
        UserComment userComment = userCommentApi.likeOrUnlike(objectId,type);

        String key = Constants.VIDEO_COMMENT_HASHKEY + "_" + userComment.getVUserId();
        String hashKey = Constants.VIDEO_COMMENT_HASHKEY + "_" + UserHolder.getUserId();
        redisTemplate.opsForHash().delete(key, hashKey);
    }
}
